package com.niiwoo.civet.user.service.local;

import com.alibaba.fastjson.JSONObject;
import com.niiwoo.activity.event.constant.BizEventRabbitConstant;
import com.niiwoo.activity.event.dto.request.UserRealNameReqDTO;
import com.niiwoo.civet.user.constants.LoginAccountErrorCode;
import com.niiwoo.civet.user.dao.aggregation.QueryUserBasicInfo;
import com.niiwoo.civet.user.dao.entity.*;
import com.niiwoo.civet.user.dao.mapper.DataStatusMapperExt;
import com.niiwoo.civet.user.dao.mapper.IdentityInfoMapperExt;
import com.niiwoo.civet.user.dao.mapper.IdentityMappingMapper;
import com.niiwoo.civet.user.dao.mapper.UserImageFileMapperExt;
import com.niiwoo.civet.user.dto.response.QueryBasicInfoResponseDTO;
import com.niiwoo.civet.user.dto.response.UserIdentityInfoResponseDTO;
import com.niiwoo.civet.user.dto.response.UserPortraitParamDTO;
import com.niiwoo.civet.user.enums.OCRChannelEnum;
import com.niiwoo.civet.user.enums.UserDataStatusEnum;
import com.niiwoo.civet.user.enums.UserDataTypeEnum;
import com.niiwoo.civet.user.enums.UserEnum;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.base.utils.IdCardUtils;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.*;
import java.util.stream.Stream;

/**
 * 用户身份信息本地服务
 */
@Slf4j
@Service
public class UserIdentityService {

    @Autowired
    IdentityInfoMapperExt identityInfoMapperExt;

    @Autowired
    UserImageFileMapperExt userImageFileMapper;

    @Autowired
    DataStatusMapperExt dataStatusMapperExt;

    @Autowired
    IdentityMappingMapper identityMappingMapper;

    @Autowired
    SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    private MobileIdentityService mobileIdentityService;

    @Autowired
    UserBasicInfoService userBasicInfoService;

    @Autowired
    PrivacyMasks privacyMasks;

    @Autowired
    RabbitTemplate rabbitTemplate;

    /**
     * 获取用户身份记录
     *
     * @param userId 用户id
     */
    public IdentityInfo getByUserId(String userId) {
        return identityInfoMapperExt.selectByPrimaryKey(userId);
    }
    
    public List<UserIdentityInfoResponseDTO> queryUserIdentityListByUserIdSet(Set<String> userIdSet) {
    	List<UserIdentityInfoResponseDTO> result = new ArrayList<UserIdentityInfoResponseDTO>();
    	List<IdentityInfo> identityInfoList = identityInfoMapperExt.queryUserIdentityListByUserIdSet(userIdSet);
    	for (IdentityInfo identityInfo : identityInfoList) {
    		UserIdentityInfoResponseDTO dto = new UserIdentityInfoResponseDTO();
    		BeanUtils.copyProperties(identityInfo, dto);
    		result.add(dto);
		}
    	 
    	 return result;
    }

    /**
     * 更新认证的OCR信息
     *
     * @param info 身份信息
     * @param isOCRStatusRecordExists OCR状态记录是否存在
     * @param dataStatus 二要素状态记录
     * @param frontImage 正面照
     * @param backImage 反面照
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public boolean updateAuthInfo(IdentityInfo info, boolean isOCRStatusRecordExists, DataStatus dataStatus, UserImageFile frontImage, UserImageFile backImage,UserImageFile handImage) {
        // 更新或新增身份信息记录
        boolean isUpdateInfoSuccess = identityInfoMapperExt.selectByPrimaryKey(info.getUserId()) != null ? identityInfoMapperExt.updateByPrimaryKeySelective(info) > 0 : identityInfoMapperExt.insertSelective(info) > 0;
        // 更新或新增OCR状态
        boolean isUpdateStatusSuccess = isUpdateInfoSuccess && (isOCRStatusRecordExists ? dataStatusMapperExt.updateByPrimaryKeySelective(dataStatus) > 0 : dataStatusMapperExt.insertSelective(dataStatus) > 0);
        // 更新图片信息
        if(handImage == null){
            return isUpdateStatusSuccess && batchUpdateImages(info.getUserId(), frontImage, backImage);
        }else{
            return isUpdateStatusSuccess && batchUpdateImages(info.getUserId(), frontImage, backImage,handImage);
        }
    }

    /**
     * 更新未认证的OCR信息
     *
     * @param isOCRStatusRecordExists OCR状态记录是否存在
     * @param dataStatus 二要素状态记录
     * @param frontImage 正面照
     * @param backImage 反面照
     * @param handImage 手持照
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public boolean updateNotAuthInfo(Optional<IdentityInfo> IdentityInfoOpt, boolean isOCRStatusRecordExists, DataStatus dataStatus, UserImageFile frontImage, UserImageFile backImage, UserImageFile handImage) {
        // 存在身份记录，则更新OCR渠道为空
        boolean isUpdateInfoSuccess = IdentityInfoOpt.map(info -> {
            IdentityInfo updateInfo = new IdentityInfo();
            updateInfo.setUserId(info.getUserId());
            updateInfo.setOcrChannel(OCRChannelEnum.EMPTY.getValue());
            return identityInfoMapperExt.updateByPrimaryKeySelective(updateInfo) > 0;
        }).orElse(true);
        // 更新或新增OCR状态
        boolean isUpdateStatusSuccess = isUpdateInfoSuccess && (isOCRStatusRecordExists ? dataStatusMapperExt.updateByPrimaryKeySelective(dataStatus) > 0 : dataStatusMapperExt.insertSelective(dataStatus) > 0);
        // 更新图片信息
        return isUpdateStatusSuccess && batchUpdateImages(frontImage.getUserId(), frontImage, backImage, handImage);
    }

    /**
     * 批量处理图片: 标记删除再新增
     *
     * @param userId 用户ID
     * @param imageFiles 图片记录
     */
    private boolean batchUpdateImages(String userId, UserImageFile... imageFiles) {
        Stream.of(imageFiles).forEach(imageFile ->
                Optional.ofNullable(userImageFileMapper.selectBySubType(userId, imageFile.getDataType(), imageFile.getSubType()))
                        .ifPresent(oldImage -> userImageFileMapper.updateDelStatusById(oldImage)) //
        );
        Stream.of(imageFiles).forEach(imageFile -> {
            if (userImageFileMapper.insertSelective(imageFile) <= 0) {
                throw new BizException(LoginAccountErrorCode.SAVE_OCR_IMAGE_FAIL);
            }
        });
        return true;
    }


    /**
     * 通过开户修改状态
     *
     * @param isOpenAccountStatusExists 开户状态是否存在
     * @param updateOpenAccountStatus 开户状态记录
     * @param isTwoElementStatusExists 二要素状态是否存在
     * @param updateTwoElementStatus 二要素状态记录
     * @param isIdentityMappingExists 身份映射是否存在
     * @param updateIdentityMapping 身份映射记录
     * @param isIdentityInfoExists 身份信息是否存在
     * @param updateIdentityInfo 身份信息记录
     * @param basicInfo 基础信息
     * @param updateOCRStatusOpt OCR状态记录， 存在则更新
     * @param updatePortraitStatusOpt 肖像认证状态记录， 存在则更新
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public boolean updateAuthInfoByOpenAccount(boolean isOpenAccountStatusExists, DataStatus updateOpenAccountStatus, boolean isTwoElementStatusExists, DataStatus updateTwoElementStatus, boolean isIdentityMappingExists, IdentityMapping updateIdentityMapping, boolean isIdentityInfoExists, IdentityInfo updateIdentityInfo, UserBasicInfo basicInfo, Optional<DataStatus> updateOCRStatusOpt, Optional<DataStatus> updatePortraitStatusOpt) {
        boolean isUpdate = false;
        // 开户状态
        if (isOpenAccountStatusExists) {
            isUpdate = dataStatusMapperExt.updateByUserIdAndTypeIfPossible(updateOpenAccountStatus, UserDataStatusEnum.OpenBankAccountStatus.PASS_BIND.getStatus()) > 0;
        } else {
            isUpdate = dataStatusMapperExt.insertSelective(updateOpenAccountStatus) > 0;
        }
        if (!isUpdate) {
            return false;
        }
        // 二要素
        if (isTwoElementStatusExists) {
            dataStatusMapperExt.updateByUserIdAndType(updateTwoElementStatus);
        } else {
            dataStatusMapperExt.insertSelective(updateTwoElementStatus);
        }
        // 身份映射
        if (isIdentityMappingExists) {
            identityMappingMapper.updateByPrimaryKeySelective(updateIdentityMapping);
        } else {
            identityMappingMapper.insertSelective(updateIdentityMapping);
        }
        // 身份信息
        if (isIdentityInfoExists) {
            identityInfoMapperExt.updateByPrimaryKeySelective(updateIdentityInfo);
        } else {
            identityInfoMapperExt.insertSelective(updateIdentityInfo);
        }
        // 性别
        Optional.ofNullable(basicInfo).ifPresent(b -> userBasicInfoService.updateInfo(b));
        // OCR
        updateOCRStatusOpt.ifPresent(dataStatus -> dataStatusMapperExt.updateByUserIdAndType(dataStatus));
        // 肖像
        updatePortraitStatusOpt.ifPresent(dataStatus -> dataStatusMapperExt.updateByUserIdAndType(dataStatus));
        mobileIdentityService.insertMappingData(updateIdentityMapping.getUserId());
        return true;
    }

    /**
     * 实名认证后，尝试更新认证信息
     * @param userId 用户id
     * @param name 姓名
     * @param encryptIdCard 身份证号 (加密)
     * @param plainIdCard 身份证号(明文)
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public boolean tryUpdateAuthInfoByReamNameAuth(String userId, String name, String encryptIdCard, String plainIdCard) {
        // 尝试更新二要素状态
        boolean isUpdateStatusSuccess = Optional.ofNullable(dataStatusMapperExt.selectByUserIdAndType(userId, UserDataTypeEnum.TWO_ELEMENT.getValue()))
                                                .map(dataStatus -> {
                                                    if (dataStatus.getDataStatus().equals(UserDataStatusEnum.RealNameAuthStatus.PASS_CERTIFIED.getStatus())) {
                                                        return false;
                                                    }
                                                    DataStatus updateStatus = new DataStatus();
                                                    updateStatus.setUserId(userId);
                                                    updateStatus.setDataType(UserDataTypeEnum.TWO_ELEMENT.getValue());
                                                    updateStatus.setDataStatus(UserDataStatusEnum.RealNameAuthStatus.PASS_CERTIFIED.getStatus());
                                                    updateStatus.setAuthTime(new Date());
                                                    return dataStatusMapperExt.updateByUserIdAndTypeIfPossible(updateStatus, UserDataStatusEnum.RealNameAuthStatus.PASS_CERTIFIED.getStatus()) > 0;
                                                })
                                                .orElseGet(() -> {
                                                    DataStatus updateStatus = new DataStatus();
                                                    updateStatus.setId(snowflakeIdWorker.nextId());
                                                    updateStatus.setUserId(userId);
                                                    updateStatus.setDataType(UserDataTypeEnum.TWO_ELEMENT.getValue());
                                                    updateStatus.setDataStatus(UserDataStatusEnum.RealNameAuthStatus.PASS_CERTIFIED.getStatus());
                                                    updateStatus.setAuthTime(new Date());
                                                    updateStatus.setCreateTime(new Date());
                                                    return dataStatusMapperExt.insertSelective(updateStatus) > 0;
                                                });
        // 如果二要素状态更新成功
        if (isUpdateStatusSuccess) {

            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    super.afterCommit();
                    try {
                        UserRealNameReqDTO json = new UserRealNameReqDTO();
                        json.setUserId(userId);
                        json.setIdentityCard(privacyMasks.encryptPrivacy(privacyMasks.decryptPrivacy(encryptIdCard).toUpperCase()));
                        json.setRealNameDate(new Date());
                        json.setUpdateDate(new Date());
                        log.info("实名认证###标签-实名认证, data={}", JSONObject.toJSONString(json));
                        rabbitTemplate.convertAndSend(BizEventRabbitConstant.Exchange.BIZ_EVENT_DIRECT_EXCHANGE, BizEventRabbitConstant.Key.BIZ_EVENT_USER_REAL_NAME_KEY, json);
                    } catch (Exception e) {
                        log.error(String.format("实名认证###标签-实名认证, 异常=%s", e.getMessage()), e);
                    }
                }
            });

            String idCard = privacyMasks.decryptPrivacy(encryptIdCard);
            String encryptIdCardUnpper = privacyMasks.encryptPrivacy(idCard.toUpperCase());

            // 1. 新增身份映射, 不存在则插入
            if (identityMappingMapper.selectByPrimaryKey(encryptIdCardUnpper) == null) {
                IdentityMapping mapping = new IdentityMapping();
                mapping.setUserId(userId);
                mapping.setIdCard(encryptIdCardUnpper);
                mapping.setCreateTime(new Date());
                identityMappingMapper.insertSelective(mapping);
            }

            String addressCode = plainIdCard.substring(0, 6);
            UserEnum.Gender gender = Integer.valueOf(plainIdCard.substring(16, 17)) % 2 == 0 ? UserEnum.Gender.FEMALE : UserEnum.Gender.MALE;
            Date birthday = IdCardUtils.getBirthdayByIdCard(plainIdCard);

            // 2. 修改身份信息
            boolean isUpdateInfoSuccess = Optional.ofNullable(identityInfoMapperExt.selectByPrimaryKey(userId))
                                                    .map(identityInfo -> {
                                                        IdentityInfo updateInfo = new IdentityInfo();
                                                        updateInfo.setUserId(identityInfo.getUserId());
                                                        updateInfo.setName(name);
                                                        updateInfo.setSex(Integer.valueOf(gender.getValue()).byteValue());
                                                        updateInfo.setIdCard(encryptIdCardUnpper);
                                                        updateInfo.setAddressCode(addressCode);
                                                        updateInfo.setBirthday(birthday);
                                                        return identityInfoMapperExt.updateByPrimaryKeySelective(updateInfo) > 0;
                                                    })
                                                    .orElseGet(()-> {
                                                        IdentityInfo updateInfo = new IdentityInfo();
                                                        updateInfo.setUserId(userId);
                                                        updateInfo.setName(name);
                                                        updateInfo.setIdCard(encryptIdCardUnpper);
                                                        updateInfo.setSex(Integer.valueOf(gender.getValue()).byteValue());
                                                        updateInfo.setAddressCode(addressCode);
                                                        updateInfo.setBirthday(birthday);
                                                        updateInfo.setOcrChannel(OCRChannelEnum.EMPTY.getValue());
                                                        updateInfo.setCreateTime(new Date());
                                                        updateInfo.setNation("");
                                                        updateInfo.setAddress("");
                                                        updateInfo.setSigningAuthority("");
                                                        return identityInfoMapperExt.insertSelective(updateInfo) > 0;
                                                    });
            // 3. 修改个人信息
            UserBasicInfo basicInfo = new UserBasicInfo();
            basicInfo.setUserId(userId);
            basicInfo.setGender(Integer.valueOf(gender.getValue()).byteValue());
            boolean isUpdateBasicSuccess = userBasicInfoService.updateInfo(basicInfo);
            return isUpdateInfoSuccess && isUpdateBasicSuccess;
        } else {
            return false;
        }
    }


    /**
     * 查找身份证号码映射
     * @param idCardNo 身份证号(加密)
     * @return
     */
    public IdentityMapping getMapping(String idCardNo) {
        return identityMappingMapper.selectByPrimaryKey(idCardNo);
    }


    /**
     * 查询用户画像需要的参数
     * @param userId
     * @return
     */
    public UserPortraitParamDTO queryUserPortraitParam(String userId) {
        return identityInfoMapperExt.queryUserPortraitParam(userId);
    }

    public String queryUserIdByIdCard(String idCard) {
        return identityInfoMapperExt.queryUserIdByIdCard(idCard);
    }


    /**
     * 根据用户身份证查询用户认证信息
     * @param idCard 用户身份证
     * @return responseDTO
     */
    public QueryBasicInfoResponseDTO queryUserAuthenticationInfo(String idCard){
        QueryUserBasicInfo queryUserBasicInfo = identityInfoMapperExt.queryUserAuthenticationInfo(idCard);
        if(queryUserBasicInfo == null)
            return null;
        QueryBasicInfoResponseDTO responseDTO = new QueryBasicInfoResponseDTO();
        responseDTO.setUserId(queryUserBasicInfo.getUserId());
        responseDTO.setMobileNo(queryUserBasicInfo.getMobileNo());
        responseDTO.setNickName(queryUserBasicInfo.getNickName());
        responseDTO.setHeadImage(queryUserBasicInfo.getHeadImage());
        responseDTO.setRegisterDate(queryUserBasicInfo.getCreateTime());
        responseDTO.setIdcard(queryUserBasicInfo.getIdCard());
        responseDTO.setRealName(queryUserBasicInfo.getRealName());
        return responseDTO;
    }

    /**
     * 根据真实姓名查询身份列表
     * @param realName
     * @return
     */
    public List<IdentityInfo> queryIdentityInfoListByRealName(String realName){
        return identityInfoMapperExt.selectListByRealName(realName);
    }
}
